﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Windows.Media.Imaging;

using System.IO.IsolatedStorage;
using System.IO;
using System.Text;
using System.Windows.Media.Effects;

namespace GameEngine.Weather
{
    public class WeatherEffect
    {
        /// <summary>
        ///     Random number generator.
        /// </summary>
        protected static Random _random = new Random();


        /// <summary>
        ///     Represents one particle of the effect(one raindrop, one snowflake, etc.)
        /// </summary>
        protected WriteableBitmap _weatherParticle;
        /// <summary>
        ///     Bitmap with the effect.
        /// </summary>
        protected WriteableBitmap _weatherLayer;
        /// <summary>
        ///     Where are the particles located.
        /// </summary>
        protected List<IntPoint> _positions = new List<IntPoint>();
        /// <summary>
        ///     Size of the whole map for which the effect is applied.
        /// </summary>
        protected IntSize _mapSize;
        /// <summary>
        ///     Used for updating positions.
        /// </summary>
        protected double _elapsedSeconds = 0.0;
        /// <summary>
        ///     True if effect has changed.
        /// </summary>
        protected bool _changed = false;
        /// <summary>
        ///     Strength of the wind.
        /// </summary>
        protected int _windStrength = 0;
        /// <summary>
        ///     Change in position on X axis.
        /// </summary>
        protected double _XPosChange = 0.0;
        /// <summary>
        ///     Constant affecting the starting positions based on wind.
        /// </summary>
        protected int _windFactor;


        /// <summary>
        ///     Creates a new weather effect.
        /// </summary>
        /// <param name="numberOfParticles">Number of Snowflakes to use.</param>
        /// <param name="mapSize">Size of the whole map.</param>
        public WeatherEffect(int numberOfParticles, IntSize mapSize, int windStrength)
        {
            this._mapSize = mapSize;
            this._windStrength = windStrength;
            if (_windStrength < 0)
                _windFactor = -20;
            else if (_windFactor > 0)
                _windFactor = 20;
            else
                _windFactor = 0;

            for (int i = 0; i < numberOfParticles; i++)
            {
                //generates new random positions for the particles
                IntPoint temp = new IntPoint(_random.Next(-_windStrength * _windFactor, _mapSize.Width + _windStrength * _windFactor), _random.Next(0, _mapSize.Height));
                _positions.Add(temp);
            }

            _weatherLayer = new WriteableBitmap(mapSize.Width, mapSize.Height);
        }


        /// <summary>
        ///     Renders the particle into the bitmap.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void _weatherParticle_ImageOpened(object sender, RoutedEventArgs e)
        {
            _weatherParticle = new WriteableBitmap((int)(sender as Image).ActualWidth, (int)(sender as Image).ActualHeight);
            _weatherParticle.Render((sender as Image), null);
            _weatherParticle.Invalidate();
        }


        /// <summary>
        ///     Returns the bitmap with the weather effect.
        /// </summary>
        /// <param name="mapPartSize">Size of the map part which we want to cover with this effect.</param>
        /// <returns></returns>
        public virtual WriteableBitmap GetEffect()
        {
            if (_weatherParticle != null && _changed)
            {
                _weatherLayer.Clear(Colors.Transparent);
                Rect source = new Rect(0, 0, _weatherParticle.PixelWidth, _weatherParticle.PixelHeight);
                Rect dest = new Rect(0, 0, _weatherParticle.PixelWidth, _weatherParticle.PixelHeight);

                //renders each snowflake into the bitmap
                foreach (IntPoint item in this._positions)
                {
                    dest.X = item.X;
                    dest.Y = item.Y;
                    _weatherLayer.Blit(dest, _weatherParticle, source, WriteableBitmapExtensions.BlendMode.AlphaBlend);
                }

                _weatherLayer.Invalidate();
                this._changed = false;
            }
            return _weatherLayer;
        }


        /// <summary>
        ///     Updates particles positions based on elapsed time.
        /// </summary>
        /// <param name="elapsedTime">Time elapsed from previous call.</param>
        public virtual void Update(TimeSpan elapsedTime)
        {
            this._elapsedSeconds += elapsedTime.TotalSeconds;

            //only updates postions every 0.01s
            if (this._elapsedSeconds > 0.01)
            {
                int temp = (int)(this._elapsedSeconds / 0.01);
                foreach (IntPoint item in this._positions)
                {
                    item.Y += temp;

                    //random snowflake movement
                    /*int value = _random.Next(20);
                    if (value == 2)
                    {
                        if (_XPosChange >= 1 || _XPosChange <= -1)
                            _XPosChange = 0;
                        else
                        {
                            int rand = _random.Next(3);
                            if (rand == 0)
                                _XPosChange = 0;
                            else if (rand == 1)
                                _XPosChange = 1;
                            else if (rand == 2)
                                _XPosChange = -1;
                        }
                    }*/

                    //wind effect
                    item.X += (int)(_windStrength * temp >> 3);
                    //item.X += (int)(_windStrength * temp /10);
                    //item.X += (int)(_XPosChange  + _windStrength * 0.1);

                    //if it flies off the screen
                    if (item.Y > this._mapSize.Height)
                    {
                        item.Y -= this._mapSize.Height;
                        item.X = _random.Next(-_windStrength * _windFactor, _mapSize.Width + _windStrength * _windFactor);
                    }

                    if (_windStrength >= 0 && item.X > this._mapSize.Width)
                    {
                        //item.X = _random.Next(-_windStrength * _windFactor, _mapSize.Width + _windStrength * _windFactor);
                        item.X = _random.Next(-_windStrength * _windFactor, _mapSize.Width);
                        //item.Y = 0;
                    }
                    else if (_windStrength <= 0 && item.X < 0)
                    {
                        //item.X = _random.Next(-_windStrength * _windFactor, _mapSize.Width + _windStrength * _windFactor);
                        item.X = _random.Next(0, _mapSize.Width + _windStrength * _windFactor);
                        //item.Y = 0;
                    }
                }

                this._elapsedSeconds = 0;
                this._changed = true;
            }
        }
    }
}
